﻿using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using System;

public class PlayerManager
{
    public PlayerManager(Player p1, Player p2, CrossVal p1Val = CrossVal.black, CrossVal p2Val = CrossVal.white)
    {
        currentPlayer = p1;
        P1 = p1;
        P2 = p2;
        P1Value = p1Val;
        P2Value = p2Val;
    }
    public void SetData(Player p1, Player p2, CrossVal p1Val = CrossVal.black, CrossVal p2Val = CrossVal.white)
    {
        currentPlayer = p1;
        P1 = p1;
        P2 = p2;
        P1Value = p1Val;
        P2Value = p2Val;
    }
    public void Change()
    {
        if(currentPlayer == P1)
        {
            currentPlayer = P2;
        }
        else
        {
            currentPlayer = P1;
        }
    }

    public Player CurrentPlayer
    {
        get
        {
            return currentPlayer;
        }
        set
        {
            currentPlayer = value;
        }
    }
    public CrossVal GetPlayerValue(Player p)
    {
        if (p == P1)
            return P1Value;
        else if (p == P2)
            return P2Value;
        else
            return CrossVal.nil;
    }
    /// <summary>
    /// 得到当前下棋玩家对应的棋子
    /// </summary>
    /// <returns></returns>
    public CrossVal GetPlayerValue()
    {
        if (currentPlayer == P1)
            return P1Value;
        else
            return P2Value;
    }
    public bool IsAIValue(CrossVal val)
    {
        if(val == P1Value)
        {
            if (P1 == Player.AI_1 || P1 == Player.AI_2)
                return true;
        }else if(val == P2Value)
        {
            if (P2 == Player.AI_1 || P2 == Player.AI_2)
                return true;
        }
        return false;
    }

    private Player currentPlayer;
    private Player P1;
    private Player P2;
    public CrossVal P1Value;
    public CrossVal P2Value;
}

public class Datacenter {
    static CrossVal[,] broadMap = new CrossVal[Constant.CrossCount, Constant.CrossCount];
    public static event Action<Point, CrossVal> OnMapDataChanged;
    public static event Action<CrossVal> OnGameEnded;
    public static event Action OnGameReplay;
    static Stack<Record> recordStack = new Stack<Record>();
    public static PlayerManager playerManager;
    static ZllFirst zll_1;
    static ZllSecond zll_2;

    static Datacenter()
    {
        playerManager = new PlayerManager(Player.Person1, Player.AI_1);
        Reset();
    }

    public static void Reset()
    {
        for (int i = 0; i < Constant.CrossCount; i++)
            for (int j = 0; j < Constant.CrossCount; j++)
                broadMap[i, j] = CrossVal.nil;

        playerManager.SetData(Player.Person1, Player.AI_2);

        zll_1 = new ZllFirst();
        zll_2 = new ZllSecond();
        
        if (OnGameReplay != null)
            OnGameReplay.Invoke();
    }

    public static void BackChess()
    {
        if(recordStack.Count > 0)
        {
            Record record = recordStack.Pop();
            SetMapValue(record.pt, CrossVal.nil, false);
            if (playerManager.IsAIValue(record.value))
            {
                BackChess();
            }
        }
    }

    public static void OnAiDown(Player ai)
    {
        //如果轮到AI, 则执行
        switch (ai)
        {
            case Player.AI_1:
                //Point downPt = zll_1.Execute(broadMap, pt);
                //DownChess(downPt);
                break;
            case Player.AI_2:
                Point downPt2 = zll_2.Excute(broadMap, playerManager.GetPlayerValue());
                DownChess(downPt2);
                break;
        }
    }

    public static void OnCross(Point pt)
    {
        //如果轮到AI下，则return
        if(playerManager.IsAIValue(playerManager.GetPlayerValue()))
            return;

        DownChess(pt);
    }

    public static void DownChess(Point pt)
    {
        if (broadMap[pt.x, pt.y] != CrossVal.nil)
            return;

        SetMapValue(pt, playerManager.GetPlayerValue());

        //判定输赢
        if (CheckLink(pt) >= Constant.GobangNum)
        {
            if(OnGameEnded != null)
                OnGameEnded(playerManager.GetPlayerValue());
        }

        //切换棋手
        playerManager.Change();

        //如果轮到AI, 则执行
        switch(playerManager.CurrentPlayer)
        {
            case Player.AI_1:
                Point downPt = zll_1.Execute(broadMap, pt);
                DownChess(downPt);
                break;
            case Player.AI_2:
                Point downPt2 = zll_2.Excute(broadMap, playerManager.GetPlayerValue());
                DownChess(downPt2);
                break;
        }
    }

    static void SetMapValue(Point pt, CrossVal val, bool bAddRecord = true)
    {
        if(GetMapValue(pt) != CrossVal.out_of_range)
        {
            broadMap[pt.x, pt.y] = val;
            OnMapDataChanged(pt, val);
            if(bAddRecord)
                recordStack.Push(new Record() { value = playerManager.GetPlayerValue(), pt = pt });
        }
    }

    static CrossVal GetMapValue(Point pt)
    {
        if (pt.x < 0 || pt.y < 0)
            return CrossVal.out_of_range;
        if (pt.x >= Constant.CrossCount || pt.y >= Constant.CrossCount)
            return CrossVal.out_of_range;
        return broadMap[pt.x, pt.y];
    }

    static int CheckLinkOfOneDirection(Point pt, Point direction)
    {
        if (direction.x == 0 && direction.y == 0)
            return 1;

        CrossVal val = GetMapValue(pt);
        int linkNum = 1;
        for (int i = 1; i<Constant.GobangNum; i++)
        {
            if (GetMapValue(pt + i * direction) == val)
            {
                linkNum++;
            }
            else
                break;
        }

        direction = -1 * direction;
        for (int i = 1; i < Constant.GobangNum; i++)
        {
            if (GetMapValue(pt + i * direction) == val)
            {
                linkNum++;
            }
            else
                break;
        }

        return linkNum;
    }

    /// 向垂直方向检索相同棋子的个数
    static int CheckVerticalLink(Point pt)
    {
        return CheckLinkOfOneDirection(pt, new Point(0, 1));
    }

    /// 向水平方向检索相同类型棋子的个数
    static int CheckHorizontalLink(Point pt)
    {
        return CheckLinkOfOneDirection(pt, new Point(1, 0));
    }

    /// 向左上斜角方向检索相同类型棋子的个数
    static int CheckLeftBevelLink(Point pt)
    {
        return CheckLinkOfOneDirection(pt, new Point(-1, 1));
    }

    /// 向右上斜角方向检索相同类型棋子的个数
    static int CheckRightBevelLink(Point pt)
    {
        return CheckLinkOfOneDirection(pt, new Point(1, 1));
    }

    /// 检查定点周围的最大连接情况
    public static int CheckLink(Point pt)
    {
        int linkNum = 1;
        linkNum = Mathf.Max(CheckVerticalLink(pt), linkNum);
        linkNum = Mathf.Max(CheckHorizontalLink(pt), linkNum);
        linkNum = Mathf.Max(CheckLeftBevelLink(pt), linkNum);
        linkNum = Mathf.Max(CheckRightBevelLink(pt), linkNum);
        //Debug.Log("linkNum : " + linkNum);
        return linkNum;
    }
}
